package com.benmei.weike.service;

import com.benmei.weike.common.Constants;
import com.benmei.weike.dao.*;
import com.benmei.weike.dto.IntoClassRoom.*;
import com.benmei.weike.dto.LeaveClassRoom.LeaveClassRoomRequest;
import com.benmei.weike.entity.*;
import com.benmei.weike.exception.ClientException;
import com.benmei.weike.getuipush.AndroidReserveTeacher;
import com.benmei.weike.getuipush.IosReserveTeacher;
import com.benmei.weike.util.DateUtil;
import com.benmei.weike.util.SMSUtil;
import com.benmei.weike.util.SendMailUtil;
import com.benmei.weike.util.Sms;
import com.nativetalk.bean.member.TdNtMember;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.apache.commons.collections.map.HashedMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * Created by Peter on 2017/9/6.
 */
@Service
public class AppointmentService {
    public static final Logger logger = LoggerFactory.getLogger(AppointmentService.class);

    @Resource
    private AppointmentDao appointmentDao;

    @Resource
    private ClassRoomDao classRoomDao;

    @Resource
    private WebsiteConfigDao websiteConfigDao;

    @Resource
    private CourseInfoDao courseInfoDao;

    @Resource
    private TeacherDao teacherDao;

    @Resource
    private StudentDao studentDao;

    @Resource
    private CoursePictureDao coursePictureDao;

    @Resource
    private ClassRoomEntryLogDao classRoomEntryLogDao;

    @Resource
    private MemberCourseDao memberCourseDao;


    /**
     * 添加一个预约信息。学生预约老师
     *
     * @param appointment
     */
    @Transactional
    public void studentAppointTeacher(Appointment appointment, TdNtMember member) {
        // 3. 查询该课程下学生已购买的、可预约次数>0的、最快失效的套餐（因为一门课学生可以买多次，即将过期的套餐优先预约），如
        Setmeal membSetmeal = appointmentDao.findFirstExpireSetmeal(appointment.getMemb_id(), appointment.getCou_id());
        if (membSetmeal == null) {
            throw new ClientException("课时不足");
        }

        // 1. 查询老师该时间段是否已经被预约
        Appointment appointmentForTeacher = appointmentDao.findConflictAppointmentForTeacher(appointment.getTea_id(), appointment.getReserve_start_time(), appointment.getReserve_end_time());
        if (appointmentForTeacher != null) {
            throw new ClientException("老师该时间已被预约,请预约其他时间或预约其他老师["+appointment.getReserve_start_time() +" - " +appointment.getReserve_end_time()+"]");
        }
        // 2. 检查该学生在该时间段是否预约了其他老师
        Appointment appointmentForMember = appointmentDao.findConflictAppointmentForMember(appointment.getTea_id(), appointment.getReserve_start_time(), appointment.getReserve_end_time());
        if (appointmentForMember != null) {
            throw new ClientException("该时间段您已预约了其他老师,请预约其他时间["+appointment.getReserve_start_time() +" - " +appointment.getReserve_end_time()+"]");
        }
        // 3. 查询老师该时间段是否为可预约状态：是否可用 0:是,1:否,2:被预约
        ReserveTime reserveTime=  appointmentDao.findConflictReserveTimeForTeacher(appointment.getTea_id(), appointment.getReserve_start_time(), appointment.getReserve_end_time(),membSetmeal.getCou_time());
        if (reserveTime != null) {
            if(ReserveTime.TimeStatus.BOOKED == reserveTime.getIs_valid().intValue()){
                throw new ClientException("老师该时间已被预约["+appointment.getReserve_start_time() +" - " +appointment.getReserve_end_time()+"]");
            }else if(ReserveTime.TimeStatus.CLOS == reserveTime.getIs_valid().intValue()){
                throw new ClientException("老师该时间未开启预约["+appointment.getReserve_start_time() +" - " +appointment.getReserve_end_time()+"]");
            }
        }
        // 4. 插入预约信息
        appointment.setReserve_time(membSetmeal.getCou_time());//1节课的时长，单位为分钟
        appointment.setReserve_end_time(DateUtil.addMinute(appointment.getReserve_start_time(),membSetmeal.getCou_time()));//预约结束时间 =  预约开始时间 + 1节课的时长
        appointment.setState(Constants.ReserveState.ready_to_begin);//待上课
        appointment.setType(Constants.ReserveType.setmeal_course);//类型为购买课程预约
        appointment.setMemb_set_id(membSetmeal.getMemb_set_id());
        Date roomOpenTime = DateUtil.addMinute(appointment.getReserve_start_time(), -10);
        appointment.setRoom_open_time(roomOpenTime);
        Date roomCloseTime = DateUtil.addMinute(appointment.getReserve_end_time(), 10);
        appointment.setRoom_close_time(roomCloseTime);
        appointmentDao.insertSelective(appointment);

        // 5. 更新该套餐的可预约次数 set_reserve_size
        appointmentDao.updateAppointmentSize(membSetmeal.getSet_reserve_size() - 1, membSetmeal.getMemb_set_id());

        // 6. 更新老师开通的时间段状态为已预约
        TeacherAppointmentTime teacherAppointmentTime = new TeacherAppointmentTime();
        teacherAppointmentTime.setTea_id(appointment.getTea_id());
        teacherAppointmentTime.setDate(appointment.getReserve_start_time());
        teacherAppointmentTime.setIs_valid(Constants.ReserveTimeState.booked);
        appointmentDao.updateAppointmentTimeStatus(teacherAppointmentTime);

        // 7. 创建教室
        ClassRoom classRoom = new ClassRoom();
        classRoom.setReserve_id(appointment.getReserve_id());
        classRoom.setTea_id(appointment.getTea_id());
        classRoom.setMemb_id(appointment.getMemb_id());
        classRoom.setCou_id(appointment.getCou_id());
        classRoom.setMemb_set_id(appointment.getMemb_set_id());
        classRoom.setRoom_state(Constants.RoomState.close);
        classRoom.setRoom_create_date(new Date());
        classRoom.setRoom_open_date(roomOpenTime);
        classRoom.setRoom_close_date(roomCloseTime);
        classRoomDao.insert(classRoom);

        // 8. 给教师发推送及邮件
        try {
            sendNotifyToTeacher(appointment, member);
        } catch (Exception e) {
            logger.error("邮件或推送发送失败", e);
        }

        // 9. 给学生发短信
        try {
            logger.info("发送短信 start\n 手机号：" + member.getMemb_phone_area() + "-" + member.getMemb_phone());
            Sms sms = new Sms(member.getMemb_phone(), member.getMemb_phone_area());
            Teacher t = teacherDao.getById(appointment.getTea_id());
            CourseInfo courseInfo = courseInfoDao.getById(appointment.getCou_id());
            String content = "【外教君】 您已成功预约";
            if (courseInfo != null) {
                content += "，课程名称：《" + courseInfo.getCou_name() + "》";
            }
            if (t != null) {
                content += "，上课老师：" + t.getTea_name();
            }
            String startTime = DateUtil.format(roomOpenTime, "yyyy-MM-dd HH:mm", appointment.getClientTimeZoneId());
            String endTime = DateUtil.format(roomCloseTime, "yyyy-MM-dd HH:mm", appointment.getClientTimeZoneId());
            content += "，教室开放时间：" + startTime + " 至 " + endTime;
            SMSUtil.sendSms(sms, content);
            logger.info("发送短信 end");
        } catch (Exception e) {
            logger.error("短信发送失败", e);
        }

    }

    public static void main(String[] args) {
        Date d = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
        System.out.println(sdf.format(d));
    }

    private void sendNotifyToTeacher(Appointment appointment, TdNtMember member) {
        Teacher teacher = teacherDao.getById(appointment.getTea_id());
        if (teacher.getEqu_client_id() != null) {
            //  发推送
            try {
                String title = "NativeTalk";
                String body = "Dear NativeTalk tutor, new assignment class, please check the time for the class.\n ";
                logger.info("发推送 deviceType=" + teacher.getEqu_type() + ",  deviceId=" + teacher.getEqu_client_id());
                if (teacher.getEqu_type().equals(Constants.ClientOsType.android)) {
                    AndroidReserveTeacher.apnpush(title, body, teacher.getEqu_client_id(), appointment.getReserve_id());
                } else {
                    IosReserveTeacher.apnpush(title, body, teacher.getEqu_client_id(), appointment.getReserve_id());
                }
            } catch (Exception e) {
                logger.error("推送发送失败", e);
            }

            // 发邮件，freemarker 模板邮件
            try {
                BigDecimal tea_amount = new BigDecimal(websiteConfigDao.getData(24));//查询教学费用 老师每分钟0.2美分
                int courseDuration = appointment.getReserve_time();//预约的课程的上课时长
                BigDecimal earnMoney = tea_amount.multiply(new BigDecimal(courseDuration));//老师上完课应该赚取多少钱 = 每分钟单价 X 课程的时长（分钟）

                CourseInfo courseInfo = courseInfoDao.getById(appointment.getCou_id());// 查询课程信息

                // freemarker的model(数据模型)
                Map<String, Object> ftlModel = new HashedMap();
                ftlModel.put("tea_name", teacher.getTea_name());
                ftlModel.put("memb_name", member.getMemb_name());
                ftlModel.put("course_name", courseInfo.getCou_english_name());
                ftlModel.put("start_time", DateUtil.format(appointment.getReserve_start_time(), "MM-dd HH:mm"));
                ftlModel.put("money", earnMoney.doubleValue());

                // freemarker 初始化
                Configuration cfg = Configuration.getDefaultConfiguration();
                String path = this.getClass().getResource("/").getPath() + "email/";
                cfg.setDirectoryForTemplateLoading(new File(path));
                cfg.setDefaultEncoding("utf-8");
                Template temp = cfg.getTemplate("teacher_course_notify.ftl", "UTF-8");
                StringWriter stringWriter = new StringWriter();
                BufferedWriter bufferedWriter = new BufferedWriter(stringWriter);
                temp.process(ftlModel, stringWriter);

                String toEmail = teacher.getTea_email();//收件人邮箱
                String subject = "[NativeTalk] New Appointment";//邮件标题
                String htmlContent = stringWriter.toString();//邮件内容
                SendMailUtil.sendMail(toEmail, subject, htmlContent);// 发送邮件
            } catch (IOException e) {
                logger.error("邮件发送失败 email:" + teacher.getTea_email(), e);
            } catch (TemplateException e) {
                logger.error("邮件发送失败 email:" + teacher.getTea_email(), e);
            }
        }
    }

    /**
     * 学生或老师进入教室
     *
     * @param request
     * @return
     */
    @Transactional
    public IntoClassRoomResponse intoClassRoom(IntoClassRoomRequest request, int userRole, int userId) {
        IntoClassRoomResponse response = new IntoClassRoomResponse();
        if (request.getRoomId() == null) {

            if (userRole == Constants.UserRole.student) {// 学生进入教室
                throw new ClientException("教室不存在，请联系客服");
            } else { // 老师进入教室
                throw new ClientException("Class does not exist, please contact customer service");
            }
        }
        ClassRoom room = classRoomDao.findById(request.getRoomId());
        if (room == null) {
            if (userRole == Constants.UserRole.student) {// 学生进入教室
                throw new ClientException("教室初始化失败");
            } else { // 老师进入教室
                throw new ClientException("Class initialization failed");
            }

        }

        // 1. 教室是否开放
        if (room.getRoom_state().intValue() == Constants.ClassRoom.RoomStatus.UN_START) {
            if (userRole == Constants.UserRole.student) {// 学生进入教室
                throw new ClientException("教室未开放");
            } else { // 老师进入教室
                throw new ClientException("Class is not open yet");
            }
        } else if (room.getRoom_state().intValue() == Constants.ClassRoom.RoomStatus.END) {
            if (userRole == Constants.UserRole.student) {// 学生进入教室
                throw new ClientException("教室已关闭");
            } else { // 老师进入教室
                throw new ClientException("Class is over");
            }

        } else if (room.getRoom_state().intValue() != Constants.ClassRoom.RoomStatus.OPEN) {
            if (userRole == Constants.UserRole.student) {// 学生进入教室
                throw new ClientException("教室已关门");
            } else { // 老师进入教室
                throw new ClientException("Class is closed");
            }
        }
        IntoClassRoom classRoom = IntoClassRoom.fromEntity(room);
        response.setRoom(classRoom);

        // 2. 查询课程和PPT信息
        CourseInfo courseInfo = courseInfoDao.getById(room.getCou_id());
        if (courseInfo == null) {
            logger.error("课程不存在，couId=" + room.getCou_id());
            if (userRole == Constants.UserRole.student) {// 学生进入教室
                throw new ClientException("课程不存在");
            } else { // 老师进入教室
                throw new ClientException("Course does not exist");
            }
        }
        // 3. 查询上次课学到哪张ppt
        MemberCourse memberCourse = memberCourseDao.findByStudentIdAndCouId(room.getMemb_id(), room.getCou_id());
        Integer lastStudyPage = 0;
        if (memberCourse != null) {
            lastStudyPage = memberCourse.getStudy_page() == null ? 0 : memberCourse.getStudy_page();
        }

        // 3. 查询课程目录（章节信息）
        List<CourseChapter> courseChapterList = courseInfoDao.findChapterByCouId(room.getCou_id());
        // 如果没有章节，设置一个默认章节，不然app会崩溃
        if (courseChapterList == null || courseChapterList.size() == 0) {
            CourseChapter chapter = new CourseChapter();
            chapter.setCou_id(room.getCou_id());
            chapter.setEnd_page(0);
            chapter.setStart_page(0);
            chapter.setLevel_english_name("Chapter 1");
            chapter.setLevel_sort(1);
            courseChapterList.add(chapter);
        }

        List<IntoClassRoomCoursePpt> pictures = coursePictureDao.findByCouId(room.getCou_id());// 课程的PPT
        IntoClassRoomCourseInfo intoClassRoomCourseInfo = IntoClassRoomCourseInfo.fromEntity(courseInfo, pictures);
        intoClassRoomCourseInfo.setLastPage(lastStudyPage); // 上堂课学到的最后一张ppt
        intoClassRoomCourseInfo.setCourseChapterList(courseChapterList);
        response.setCourseInfo(intoClassRoomCourseInfo);

        // 4. 查询老师信息
        Teacher teacher = teacherDao.getById(room.getTea_id());
        if (teacher == null) {
            logger.error("老师不存在，teacherId=" + room.getTea_id());
            if (userRole == Constants.UserRole.student) {// 学生进入教室
                throw new ClientException("老师不存在");
            } else { // 老师进入教室
                throw new ClientException("No teacher in the class");
            }
        }
        IntoClassRoomTeacher intoClassRoomTeacher = IntoClassRoomTeacher.fromEntity(teacher, room);
        response.setTeacher(intoClassRoomTeacher);

        // 5. 查询学生信息
        Student student = studentDao.getById(room.getMemb_id());
        if (student == null) {
            logger.error("学生不存在，memberId=" + room.getTea_id());
            if (userRole == Constants.UserRole.student) {// 学生进入教室
                throw new ClientException("学生不存在");
            } else { // 老师进入教室
                throw new ClientException("No student in the class");
            }
        }
        IntoClassRoomStudent intoClassRoomStudent = IntoClassRoomStudent.fromEntity(student, room);
        response.setStudent(intoClassRoomStudent);


        // 6. 验证请求api的用户是否是classRoom中记录的用户
        if (Constants.UserRole.student == userRole) {
            if (student.getMemb_id() != userId) {
                logger.error("学生进错教室了，membId=" + student.getMemb_id() + "，ClassRoom membId = " + userId);
                throw new ClientException("亲，您进错教室了！");
            }
        } else {
            if (teacher.getTea_id() != userId) {
                logger.error("老师进错教室了，teaId=" + teacher.getTea_id() + "，ClassRoom teaId = " + userId);
                throw new ClientException("Oops, wrong class!");
            }
        }

        // 7. 更新老师或学生进入教室的次数
        ClassRoomEntryLog entryLog = updateIntoClassRoomNumber(userRole, room, teacher, student);

        // 8. 记录进入教室日志（进出教室，网络状态，通话状态）
        entryLog.setEvent_date(new Date());
        entryLog.setRoom_id(room.getRoom_id());
        entryLog.setUser_role(userRole);
        entryLog.setEvent_type(Constants.ClassRoom.EventType.enter);
        classRoomEntryLogDao.insert(entryLog);

        return response;
    }

    /**
     * 老师或学生离开教室
     *
     * @param request
     * @param userRole
     */
    public void leaveClassRoom(LeaveClassRoomRequest request, int userRole, int userId) {
        ClassRoom room = classRoomDao.findById(request.getRoomId());
        if (room == null) {
            if (userRole == Constants.UserRole.student) {// 学生进入教室
                throw new ClientException("教室初始化失败");
            } else { // 老师进入教室
                throw new ClientException("Class initialization failed");
            }
        }

        // 1. 查询老师信息
        Teacher teacher = teacherDao.getById(room.getTea_id());
        if (teacher == null) {
            logger.error("老师不存在，teacherId=" + room.getTea_id());
            if (userRole == Constants.UserRole.student) {// 学生进入教室
                throw new ClientException("老师不存在");
            } else { // 老师进入教室
                throw new ClientException("No Teacher in the class");
            }
        }

        // 2. 查询学生信息
        Student student = studentDao.getById(room.getMemb_id());
        if (student == null) {
            logger.error("学生不存在，memberId=" + room.getTea_id());
            if (userRole == Constants.UserRole.student) {// 学生进入教室
                throw new ClientException("学生不存在");
            } else { // 老师进入教室
                throw new ClientException("No student in the class");
            }
        }

        // 3. 更新老师或学生是否在教室里面
        if (userRole == Constants.UserRole.student) {
            // 学生离开教室
            room.setMemb_is_in_room(Constants.ClassRoom.InRoom.no);
        } else {
            // 老师离开教室
            room.setTea_is_in_room(Constants.ClassRoom.InRoom.no);
        }
        classRoomDao.update(room);

        // 3. 记录离开教室日志（进出教室，网络状态，通话状态）
        ClassRoomEntryLog entryLog = new ClassRoomEntryLog();
        entryLog.setEvent_date(new Date());
        entryLog.setRoom_id(room.getRoom_id());
        entryLog.setUser_role(userRole);
        entryLog.setUser_id(userId);
        entryLog.setEvent_type(Constants.ClassRoom.EventType.leave);
        entryLog.setLeave_reason(request.getReason());
        classRoomEntryLogDao.insert(entryLog);
    }

    private ClassRoomEntryLog updateIntoClassRoomNumber(int userRole, ClassRoom room, Teacher teacher, Student student) {
        ClassRoomEntryLog entryLog = new ClassRoomEntryLog();
        if (userRole == Constants.UserRole.student) {
            // 学生进入教室
            room.setMemb_is_in_room(Constants.ClassRoom.InRoom.yes);
            room.setMemb_into_number(room.getMemb_into_number() + 1);
            entryLog.setUser_id(student.getMemb_id());
        } else {
            // 老师进入教室
            room.setTea_is_in_room(Constants.ClassRoom.InRoom.yes);
            room.setTea_into_number(room.getMemb_into_number() + 1);
            entryLog.setUser_id(teacher.getTea_id());
        }
        classRoomDao.update(room);
        return entryLog;
    }
}
